package jacktgq.moveTheBox;

/**
 * @Author CandyWall
 * @Date 2021/3/28--23:29
 * @Description 游戏盘面
 */
public class Board {
    // 点代表当前位置为空
    public static final char EMPTY = '.';

    private int M, N;
    private char[][] data;

    // 记录当前盘面的上一个盘面
    private Board preBoard;
    // 盘面的
    private String swapString;

    public Board(String[] lines) {
        if (lines == null || lines.length == 0) {
            throw new IllegalArgumentException("游戏求解盘面不能为空");
        }
        M = lines.length;
        N = lines[0].length();
        data = new char[M][N];

        for (int i = 0; i < M; i++) {
            if (lines[i].length() != N) {
                throw new IllegalArgumentException("每一行字符的长度必须相等");
            }
            for (int j = 0; j < N; j++) {
                data[i][j] = lines[i].charAt(j);
            }
        }
    }

    public Board(Board board) {
        this(board, null, null);
    }

    public Board(Board board, Board preBoard, String swapString) {
        this.M = board.getM();
        this.N = board.getN();
        this.data = new char[M][N];
        this.preBoard = preBoard;
        this.swapString = swapString;
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                data[i][j] = board.getDataAt(i, j);
            }
        }
    }

    public int getM() {
        return M;
    }

    public int getN() {
        return N;
    }

    public char getDataAt(int x, int y) {
        return data[x][y];
    }

    public boolean inArea(int x, int y) {
        return x >= 0 && x < M && y >=0 && y < N;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                sb.append(data[i][j]);
            }
            sb.append('\n');
        }

        return sb.toString();
    }

    /**
     * 判断游戏是否胜利：判断依据，盘面上是否还有元素，没有元素就获胜了
     * @return
     */
    public boolean isWin() {
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                if (data[i][j] != EMPTY) {
                    return false;
                }
            }
        }
        printSwapInfo();
        return true;
    }

    public void swap(int i, int j, int nextI, int nextJ) {
        char t = data[i][j];
        data[i][j] = data[nextI][nextJ];
        data[nextI][nextJ] = t;
    }

    /**
     * 尝试运行盘面，执行消除操作
     */
    public void run() {
        do {
            drop();
        } while (match());
    }

    /**
     * 处理方块掉落的逻辑
     */
    private void drop() {
        // 从最下面一层开始向上遍历
        for (int j = 0; j < N; j++) {
            int cur = M - 1;
            for (int i = M - 1; i >= 0; i--) {
                if (data[i][j] != EMPTY) {
                    swap(i, j, cur, j);
                    cur--;
                }
            }
        }
    }

    /**
     * 处理方块消除的逻辑
     * @return
     */
    private boolean match() {
        boolean matched = false;
        boolean[][] tag = new boolean[M][N];
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                if (data[i][j] != EMPTY) {
                    // 遍历这个点的右和下方
                    for (int k = 0; k < 2; k++) {
                        int nextI1 = i + GameData.dirs[k][0];
                        int nextJ1 = j + GameData.dirs[k][1];
                        int nextI2 = i + GameData.dirs[k][0] * 2;
                        int nextJ2 = j + GameData.dirs[k][1] * 2;
                        if (inArea(nextI1, nextJ1) && inArea(nextI2, nextJ2) &&
                            data[i][j] == data[nextI1][nextJ1] && data[i][j] == data[nextI2][nextJ2]) {
                            tag[i][j] = true;
                            tag[nextI1][nextJ1] = true;
                            tag[nextI2][nextJ2] = true;
                            matched = true;
                        }
                    }
                }
            }
        }

        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                if (tag[i][j]) {
                    data[i][j] = EMPTY;
                }
            }
        }

        return matched;
    }

    public Board getPreBoard() {
        return preBoard;
    }

    /**
     * 打印操作步骤
     */
    public void printSwapInfo() {
        if (preBoard != null && preBoard.swapString != null) {
            preBoard.printSwapInfo();
        }
        System.out.println(swapString);
    }
}
